<template>
  <div
    class="comp-split-panel"
    :class="{
      'edit-mode': isEditMode,
    }"
  >
    <a-row
      v-show="!hideSeparatorModes.includes(splitMode) && !isEditMode"
      class="row"
    >
      <a-col :span="24" class="label">
        分隔符
      </a-col>
      <a-col :span="24" :class="{ 'has-error': hasError }">
        <span class="prefix"></span>
        <a-input
          ref="inputSeparator"
          v-model="value.separator"
          class="fix"
          size="small"
          placeholder="例如：-,."
          @input="onSeparatorInput"
        />
        <br />
        <span v-show="hasError" class="error-message">请输入分隔符</span>
      </a-col>
    </a-row>
    <a-row class="row">
      <a-col :span="24" class="label">
        拆分
      </a-col>
      <a-col :span="24">
        <span class="prefix"></span>
        <a-select
          default-value="1"
          size="small"
          :value="`${value.splitType}`"
          class="select"
          :disabled="true"
          @change="handleSplitTypeChange"
        >
          <a-select-option value="1">前</a-select-option>
          <a-select-option value="2">后</a-select-option>
          <a-select-option value="3">全部</a-select-option>
        </a-select>
        <a-select
          default-value="1"
          class="select"
          size="small"
          :value="`${value.splitNum}`"
          :disabled="value.splitType === 3"
          @change="handleSplitNumberChange"
        >
          <a-select-option v-for="item in 10" :key="item" :value="item">
            {{ item }}
          </a-select-option>
        </a-select>
        字段
      </a-col>
    </a-row>
    <a-row
      v-for="(index, key) in Math.max(parseInt(value.splitNum), 1)"
      :key="`name${index}`"
      class="row"
    >
      <a-col :span="24" class="label"> 列名{{ index }} </a-col>
      <a-col :span="24">
        <span class="prefix"></span>
        <a-input
          v-model="value.columnName[key]"
          size="small"
          class="fix"
          placeholder="请输入新列名"
          :max-length="100"
          @blur="onColumnNameBlur(key)"
        >
        </a-input>
      </a-col>
    </a-row>
  </div>
</template>
<script lang="ts">
import KV from '@/components/form/kv'
import { isArray } from 'lodash'
import { Component, Prop, Vue, Watch } from 'vue-property-decorator'
import DataStore, { OptionPreViewAction } from '@/store/modules/dataview'
import SplitInfo from './split-info-interface'

@Component({
  components: {},
})
/**
 * isEditMode 为false时用于表格操作推荐， 否则为历史记录编辑模式下的使用场景
 */
export default class SplitPanel extends Vue {
  /** 绑定值 */
  @Prop({
    type: Object,
    default() {
      return {
        separator: '',
        splitType: 1,
        splitNum: 2,
        columnName: [''],
      }
    },
  })
  value!: Object

  /** 是否为编辑模式 */
  @Prop({
    type: Boolean,
    default() {
      return false
    },
  })
  isEditMode!: boolean

  /** 编辑模式下关联的列 */
  @Prop({
    type: String,
    default() {
      return ''
    },
  })
  editBindColumn!: string

  /** 编辑模式下默认的拆分后的列名称集合 */
  @Prop({
    type: Array,
    default() {
      return []
    },
  })
  editValueColumnName!: Array<string>

  /** 拆分option */
  @Prop({
    type: String,
    default() {
      return ''
    },
  })
  splitMode!: OptionPreViewAction

  /** 需要隐藏拆分字符串编辑的模式 */
  private hideSeparatorModes: Array<string> = [
    OptionPreViewAction.selectionFilterSelectCellsSamePosSelection,
    OptionPreViewAction.selectionFilterSelectCellsStartWithAndEndWithSameWordSplitColumns,
    OptionPreViewAction.selectionFilterSelectCellsStartWithAndEndWithSameWordSplitColumns,
    OptionPreViewAction.selectionFilterSelectCellsEndWithSameWordSplitColumns,
    OptionPreViewAction.selectionFilterSelectCellsStartWithSameWordSplitColumns,
    OptionPreViewAction.selectionFilterSelectCellsStartWithAndEndWithSameWordSplitColumns,
    OptionPreViewAction.selectionFilterSelectCellsSamePosWordSplitColumns,
    OptionPreViewAction.selectionFilterSelectCellsSamePosSelectionSplitColumns,
  ]

  /** 是否有错误 */
  private hasError: boolean = false

  /** 监听value并重新舒适和 */
  @Watch('value', {
    immediate: true,
    deep: true,
  })
  getValue(newValue: any) {
    // 这里设置到stroe里面时为了预览界面跟随用户设置而改变
    this.$nextTick(() => {
      DataStore.setTableSplitInfo(newValue)
      this.syncSpitInfo()
    })
  }

  mounted() {
    this.syncSpitInfo()
  }

  /** 拆分字符编辑事件回调 */
  onSeparatorInput() {
    const config: any = this.value
    this.$emit('input', config)
  }

  /** 拆分类型编辑事件回调 */
  private handleSplitTypeChange(value: string) {
    const config: any = this.value
    config.splitType = +value
    this.$emit('input', config)
  }

  /** 自动创建列名 */
  private buildColumnNames(columnName: string) {
    const result = [] as Array<string>
    // 如果为编辑模式则优先填入旧的名称
    const editValueColumnName =
      this.isEditMode && isArray(this.editValueColumnName)
        ? this.editValueColumnName
        : []
    for (
      let i = 0;
      i < Math.max((this.value as any).splitNum as number, 1);
      i += 1
    ) {
      const newColumnName = [undefined, null, ''].includes(
        editValueColumnName[i]
      )
        ? this.getExtColumnName(columnName, result)
        : editValueColumnName[i]
      result.push(newColumnName)
    }
    return result
  }

  /**
   * 初始化，用于外部调用
   */
  init() {
    const columnName: string = DataStore.tableSelectionInfo?.columnName || ''
    const valueNew = {
      separator: '',
      splitType: 1,
      splitNum: 1,
      columnName: [this.getExtColumnName(columnName)],
    }
    this.$emit('input', valueNew)
  }

  /**
   * 获取新的列名
   */
  getExtColumnName(columnName: string, BuildNames: Array<string> = []) {
    const columns = DataStore.tableColumns.reduce(
      (rec: Array<string>, item) => {
        rec.push(item.name)
        return rec
      },
      []
    )
    let i = 0
    let columnNameNew = ''
    do {
      i += 1
      columnNameNew = `${columnName}_字段${i}`
    } while (
      columns.includes(columnNameNew) ||
      BuildNames.includes(columnNameNew)
    )
    return columnNameNew
  }

  // 拆分字段数量变更时自动填入默认字段名称
  private handleSplitNumberChange(value: string) {
    this.$nextTick(() => {
      const config: any = this.value
      config.splitNum = +value
      const columnName: string = this.isEditMode
        ? this.editBindColumn
        : DataStore.tableSelectionInfo?.columnName || ''
      const newcColumnNames = this.buildColumnNames(columnName)
      config.columnName = newcColumnNames
      this.$emit('input', config)
    })
  }

  /** 校验 */
  validate(): KV | null {
    // 如果是编辑模式，则过滤出除了上一次设置的字段的所有字段的集合
    const columnSet = this.isEditMode
      ? new Set(
          DataStore.tableColumns
            .filter((column) => {
              return !((this.editValueColumnName || []) as Array<
                string
              >).includes(column.name)
            })
            .map((item) => item.name)
        )
      : new Set(DataStore.tableColumns.map((item) => item.name))

    const columnMatched = ((this.value as any).columnName as Array<
      string
    >).find((item) => columnSet.has(item))
    if (columnMatched) {
      this.$message.info(`列名${columnMatched}已存在`)
      return null
    }
    const tag =
      (this.value as any).columnName &&
      ((this.value as any).columnName as Array<string>).every((item) => {
        return !['', null, undefined].includes(item)
      })
    if (!tag) {
      this.$message.info('请确保新列名不为空')
      return null
    }
    return {
      separator: (this.value as any).separator,
      splitType: (this.value as any).splitType,
      splitNum: (this.value as any).splitNum,
      desc: this.formatDescription,
      newCol: (this.value as any).columnName,
    } as SplitInfo
  }

  /** 初始化 */
  syncSpitInfo() {
    const Info: SplitInfo = {
      separator: (this.value as any).separator,
      splitType: (this.value as any).splitType,
      splitNum: (this.value as any).splitNum,
      desc: this.formatDescription,
      newCol: (this.value as any).columnName,
    }
    DataStore.setTableSplitInfo(Info)
  }

  /**
   * 获取元素出现的频率
   */
  getCount(arrayValues: Array<string>, value: string): number {
    let result = 0
    arrayValues.forEach((valueCurrent: String) => {
      if (valueCurrent === value) {
        result += 1
      }
    })
    return result
  }

  /**
   * 失去焦点则重新检测并将空字段名称填入默认字段名称
   */
  onColumnNameBlur(index: number) {
    const columnSet = this.isEditMode
      ? new Set(
          DataStore.tableColumns
            .filter((column) => {
              return !((this.editValueColumnName || []) as Array<
                string
              >).includes(column.name)
            })
            .map((item) => item.name)
        )
      : new Set(DataStore.tableColumns.map((item) => item.name))
    const columnNames = (this.value as any).columnName as Array<string>
    if (
      ['', null, undefined].includes(columnNames[index]) ||
      this.getCount(columnNames, columnNames[index]) > 1 ||
      columnSet.has(columnNames[index])
    ) {
      // 用户手动设置了重复的值需要清空，然后自动生成
      this.$message.info(
        columnNames[index] === '' ? '字段不能为空' : '字段已存在'
      )
      ;(this.value as any).columnName[index] = ''
      const columnName: string = DataStore.tableSelectionInfo?.columnName || ''
      const newcColumnNames = this.buildColumnNames(columnName)
      columnNames[index] = newcColumnNames[index]
      const valueNew = {
        ...(this.value as any),
        columnName: columnNames,
      }
      this.$emit('input', valueNew)
    }
  }

  /** 获取描述关键字 */
  private get formatDescription() {
    let description = `分隔符${(this.value as any).separator}，拆分`
    if ((this.value as any).splitType === 3) {
      description += '全部'
    } else {
      description += `${(this.value as any).splitType === 1 ? '前' : '后'}${
        (this.value as any).splitNum
      }个字段`
    }
    return description
  }
}
</script>
<style lang="less" scoped>
/deep/ .ant-row.row {
  margin-top: 8px;

  .prefix {
    display: inline-block;
    width: 30px;
  }

  .label {
    padding-left: 30px;
  }

  .fix {
    width: calc(100% - 30px) !important;
  }

  .select {
    margin-right: 8px;
    width: 80px;
  }

  &:last-child {
    padding-bottom: 8px;
  }
}

.edit-mode {
  /deep/ .ant-row.row {
    .label {
      padding-left: 14px;
    }

    .prefix {
      display: inline-block;
      width: 14px;
    }

    .fix {
      width: calc(100% - 14px) !important;
    }
  }
}
</style>
